﻿using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SCCodeTool
{
    public partial class FCodeTool : Form
    {
        public FCodeTool()
        {
            InitializeComponent();
        }

        private void FCodeTool_Load(object sender, EventArgs e)
        {

        }

        private void btnChioceSrcDir_Click(object sender, EventArgs e)
        {
            var fbd = new FolderBrowserDialog();
            if (fbd.ShowDialog() == DialogResult.OK)
            {
                txtSrcDir.Text = fbd.SelectedPath;
            }
        }

        private void btnChioceDocePath_Click(object sender, EventArgs e)
        {
            var sfd = new SaveFileDialog();
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                txtCodePath.Text = sfd.FileName;
            }
        }

        private string _srcDir = null;
        private string _dstFilePath = null;
        private bool _containsRefCode = false;
        private void btnMergeCode_Click(object sender, EventArgs e)
        {
            string srcDir = txtSrcDir.Text.Trim();

            if (string.IsNullOrWhiteSpace(srcDir))
            {
                MessageBox.Show("源代码目录不能为空");
                return;
            }

            if (!Directory.Exists(srcDir))
            {
                MessageBox.Show("源代码目录不存在");
                return;
            }

            string dstFilePath = txtCodePath.Text.Trim();
            if (string.IsNullOrWhiteSpace(dstFilePath))
            {
                MessageBox.Show("目标代码路径不能为空");
                return;
            }

            string dir = Path.GetDirectoryName(dstFilePath);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            this._srcDir = srcDir;
            this._dstFilePath = dstFilePath;
            this._containsRefCode = checkBoxContainsRefCode.Checked;
            btnMergeCode.Enabled = false;
            Task.Factory.StartNew(this.MergeCodeFile);
        }

        private static string[] _extensions = new string[] { "*.h", "*.c", "*.cpp", "*.cs", "*.java", "*.py" };
        private static bool IsRefCode(ref string line)
        {
            //using System;
            //using System.Collections.Generic;
            //using System.Linq;
            if (line.StartsWith("using "))
            {
                return true;
            }

            //#pragma once
            //#define WIN32_LEAN_AND_MEAN             
            //#include <windows.h>
            //#ifndef PCH_H
            //#define PCH_H
            //#include "framework.h"
            //#endif 
            //#pragma once
            if (line.StartsWith("#pragma once") ||
                line.StartsWith("#include"))
            {
                return true;
            }

            //import java.net.URL;
            //import java.io.IOException;
            if (line.StartsWith("import ")||
                line.StartsWith("from "))
            {
                return true;
            }

            return false;
        }


        private void MergeCodeFile()
        {
            try
            {
                var dirInfo = new DirectoryInfo(this._srcDir);
                using (var writer = new StreamWriter(this._dstFilePath))
                {
                    for (int i = 0; i < _extensions.Length; i++)
                    {
                        FileInfo[] fileInfos = dirInfo.GetFiles(_extensions[i], SearchOption.AllDirectories);
                        foreach (FileInfo fileInfo in fileInfos)
                        {
                            this.ReadFileCode(fileInfo, writer);
                        }
                    }
                }

                this.Invoke(new Action(() =>
                {
                    btnMergeCode.Enabled = true;
                    MessageBox.Show("ok");
                }));
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    btnMergeCode.Enabled = true;
                    MessageBox.Show(ex.Message);
                }));
            }
        }

        private void ReadFileCode(FileInfo fileInfo, StreamWriter writer)
        {
            bool startUsing = true;
            bool annotatFlag = false;
            string line, line2;
            int index, index2;

            using (var reader = new StreamReader(fileInfo.FullName))
            {
                while (true)
                {
                    line = reader.ReadLine();
                    if (line == null)
                    {
                        break;
                    }

                    line2 = line.Trim();
                    if (string.IsNullOrEmpty(line2))
                    {
                        continue;
                    }

                    if (!this._containsRefCode && startUsing)
                    {
                        if (IsRefCode(ref line2))
                        {
                            continue;
                        }
                        else
                        {
                            startUsing = false;
                        }
                    }

                    if (annotatFlag)
                    {
                        if (line2.EndsWith("*/"))
                        {
                            annotatFlag = false;
                        }

                        continue;
                    }

                    if (line2.StartsWith("//"))
                    {
                        continue;
                    }

                    if (line2.StartsWith("/*"))
                    {
                        if (!line2.EndsWith("*/"))
                        {
                            annotatFlag = true;
                        }

                        continue;
                    }

                    index = line.IndexOf("//");
                    if (index < 0)
                    {
                        index = line.IndexOf("/*");
                        if (index < 0)
                        {
                            writer.WriteLine(line);
                        }
                        else
                        {
                            index2 = line.IndexOf("*/");
                            if (index2 < 0)
                            {
                                writer.WriteLine(line.Substring(0, index));
                                annotatFlag = true;
                            }
                            else
                            {
                                writer.WriteLine(line.Substring(0, index));
                                index = index2 + 2;

                                if (index < line.Length)
                                {
                                    for (int i = 0; i < line.Length; i++)
                                    {
                                        if (line[i] != ' ' && line[i] != '\t')
                                        {
                                            writer.Write(line.Substring(0, i));
                                            break;
                                        }
                                    }
                                    writer.WriteLine(line.Substring(index));
                                }
                            }
                        }
                    }
                    else
                    {
                        writer.WriteLine(line.Substring(0, index));
                    }
                }
            }
        }

 




        private void btnStacLines_Click(object sender, EventArgs e)
        {
            string srcDir = txtSrcDir.Text.Trim();
            if (string.IsNullOrWhiteSpace(srcDir))
            {
                MessageBox.Show("源代码目录不能为空");
                return;
            }

            if (!Directory.Exists(srcDir))
            {
                MessageBox.Show("源代码目录不存在");
                return;
            }

            this._srcDir = srcDir;
            this._containsRefCode = checkBoxContainsRefCode.Checked;
            btnStacLines.Enabled = false;
            Task.Factory.StartNew(this.StaticCodeFile);
        }

        private void StaticCodeFile()
        {
            try
            {
                long count = 0;
                var dirInfo = new DirectoryInfo(this._srcDir);

                for (int i = 0; i < _extensions.Length; i++)
                {
                    FileInfo[] fileInfos = dirInfo.GetFiles(_extensions[i], SearchOption.AllDirectories);
                    foreach (FileInfo fileInfo in fileInfos)
                    {
                        count += this.StaticCode(fileInfo);
                    }
                }

                this.Invoke(new Action(() =>
                {
                    btnStacLines.Enabled = true;
                    txtCodeLines.Text = count.ToString();
                    MessageBox.Show("ok");
                }));
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    txtCodeLines.Text = "0";
                    btnStacLines.Enabled = true;
                    MessageBox.Show(ex.Message);
                }));
            }
        }

        private long StaticCode(FileInfo fileInfo)
        {
            long count = 0;
            bool annotatFlag = false;
            string line, line2;
            int index, index2;
            bool startUsing = true;

            using (var reader = new StreamReader(fileInfo.FullName))
            {
                while (true)
                {
                    line = reader.ReadLine();
                    if (line == null)
                    {
                        break;
                    }

                    line2 = line.Trim();
                    if (string.IsNullOrEmpty(line2))
                    {
                        continue;
                    }

                    if (!this._containsRefCode && startUsing)
                    {
                        if (IsRefCode(ref line2))
                        {
                            continue;
                        }
                        else
                        {
                            startUsing = false;
                        }
                    }

                    if (annotatFlag)
                    {
                        if (line2.EndsWith("*/"))
                        {
                            annotatFlag = false;
                        }

                        continue;
                    }

                    if (line2.StartsWith("//"))
                    {
                        continue;
                    }

                    if (line2.StartsWith("/*"))
                    {
                        if (!line2.EndsWith("*/"))
                        {
                            annotatFlag = true;
                        }

                        continue;
                    }

                    index = line.IndexOf("//");
                    if (index < 0)
                    {
                        index = line.IndexOf("/*");
                        if (index < 0)
                        {
                            count++;
                        }
                        else
                        {
                            index2 = line.IndexOf("*/");
                            if (index2 < 0)
                            {
                                count++;
                                annotatFlag = true;
                            }
                            else
                            {
                                count++;
                                index = index2 + 2;

                                if (index < line.Length)
                                {
                                    count++;
                                }
                            }
                        }
                    }
                    else
                    {
                        count++;
                    }
                }
            }

            return count;
        }



    }

}
